package com.nexgo.payment.trans.settle;

import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;

import com.nexgo.data.entity.RecvData;
import com.nexgo.oaf.apiv3.SdkResult;
import com.nexgo.payment.App;
import com.nexgo.payment.R;
import com.nexgo.payment.aop.annotation.ManageTransCondition;
import com.nexgo.payment.aop.annotation.TransCondition;
import com.nexgo.payment.constrant.PreferencesConstants;
import com.nexgo.payment.constrant.SettleOpType;
import com.nexgo.payment.constrant.SettlePrintState;
import com.nexgo.payment.constrant.SysConstant;
import com.nexgo.payment.constrant.TransType;
import com.nexgo.payment.databases.DataSource;
import com.nexgo.payment.databases.SettleInfo;
import com.nexgo.payment.databases.TransRecord;
import com.nexgo.payment.databases.mapper.SettleMapper;
import com.nexgo.payment.entity.TransData;
import com.nexgo.payment.trans.AbsOnlinePresenter;
import com.nexgo.payment.util.PrintHelper;
import com.nexgo.payment.util.StringUtils;
import com.nexgo.payment.util.TransUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;

import io.reactivex.subjects.BehaviorSubject;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * 结算相关操作
 *
 * @author 谭忠扬-YuriTam //xiaox 2017/9/4 下午3:54
 * @time 2017年08月29日
 */
@ManageTransCondition
@TransCondition(checkNeedSettle = false)
public class SettlePresenter extends AbsOnlinePresenter implements SettleContract.Presenter {
    private Logger mLog = LoggerFactory.getLogger(SettlePresenter.class.getSimpleName());

    private SettleContract.View mView;
    private SettleInfo mSettleInfo;
    private SettleOpType mOpType;
    private Iterator<TransRecord> mTransRecordIterator;
    private TransRecord mCurrTransRecord;
    private BehaviorSubject<TransRecord> mSubject;
    private NowDetailTask mNowDetailTask = NowDetailTask.DETAIL;
    private boolean mIsCustomerCancel;
    private Handler mHandler;

    public SettlePresenter(@NonNull SettleContract.View view, @NonNull DataSource repository, SettleOpType opType) {
        super(view, repository);
        mView = checkNotNull(view);
        mOpType = checkNotNull(opType);
        mHandler = new Handler(Looper.myLooper());
        mView.setPresenter(this);
    }

    @Override
    protected TransData getTransData() {
        TransData transData = new TransData();
        transData.setTransType(TransType.SETTLE);
        return transData;
    }

    @Override
    protected void onFirstAction() {
        //先封装交易汇总数据
        mLog.debug("当前结算操作类型 {}",mOpType);
        if (SettleOpType.REPRINT_SETTLE_INFO.equals(mOpType)) {
            mLog.debug("获取重打印结算单数据");
            mSettleInfo = mRepository.getSettleInfo();
        } else {
            mLog.debug("获取当前数据库结算单数据");
            mSettleInfo = new SettleMapper().transform(mRepository.getSuccessfulTransRecords());
        }
        if(mSettleInfo != null) {
            mSettleInfo.setBatchNum(mRepository.getParamValue(PreferencesConstants.BATCH_NUMBER));
            mSettleInfo.setDate(new SimpleDateFormat("MMdd", SysConstant.LOCALE).format(new Date()));
            mSettleInfo.setTime(new SimpleDateFormat("HHmmss", SysConstant.LOCALE).format(new Date()));
            mSettleInfo.setMerchantId(mRepository.getParamValue(PreferencesConstants.MERCHANT_ID));
            mSettleInfo.setTerminalId(mRepository.getParamValue(PreferencesConstants.TERMINAL_ID));
            mSettleInfo.setMerchantName(mRepository.getParamValue(PreferencesConstants.MERCHANT_NAME));
            mSettleInfo.setOperator(Integer.parseInt(mRepository.getParamValue(PreferencesConstants.CURRENT_OPERATOR_NO)));
        }
        //根据操作类型做出相应的动作
        switch (mOpType) {
            //正常结算流程
            case NORMAL_SETTLE:
                postMainThread(() -> mView.showStatistics(mSettleInfo, true));
                break;
            //签退结算，自动发起结算
            case LOGOUT_SETTLE:
                postMainThread(() -> mView.showStatistics(mSettleInfo, false));
                mHandler.postDelayed(() -> doSettle(), 200);
                break;
            //打印交易汇总
            case PRINT_SUM_INFO:
                postMainThread(() -> mView.showStatistics(mSettleInfo, false));
                //无交易记录时，自动退出
                if (mRepository.getSuccessfulTransRecordNum() == 0) {
                    postMainThread(() -> mView.showNoTransRecord());
                    return;
                }
                mHandler.postDelayed(() -> startPrintSum(), 200);
                break;
            //结算重打印
            case REPRINT_SETTLE_INFO:
                if (mSettleInfo == null) {
                    postMainThread(() -> mView.showNoTransRecord());
                    return;
                }
                postMainThread(() -> mView.showStatistics(mSettleInfo, false));
                mHandler.postDelayed(() -> startPrintSettle(true), 200);
                break;
            case BATCH_UPLOAD:
                postMainThread(() -> mView.showStatistics(mSettleInfo, false));
                mTransData.setTransType(TransType.BATCH_END);
                postMainThread(() -> mView.showOnlineProc(mTransData, null));
                break;
            default:
                break;
        }
    }

    @Override
    protected void onTransSuccess(RecvData recvData) {
//        if (TransType.SETTLE.equals(mTransData.getTransType())) {
        if (recvData == null ) {
                postMainThread(() -> mView.showTransFailed());
            return;
        }
        else {
            saveSettleInfo(recvData);
            updateSettleInfoBatchUploadState();
            updateSettleInfoPrintState(SettlePrintState.NONE);
            startPrintSettle(false);
        }
    }

    /**
     * 更新结算批上送状态
     */
    private void updateSettleInfoBatchUploadState() {
        SettleInfo settleInfo = mRepository.getSettleInfo();
        settleInfo.setIsBatchUploadComplete(true);
        mRepository.updateSettleInfo(settleInfo);
    }

    /**
     * 更新结算打印状态
     *
     * @param state
     */
    private void updateSettleInfoPrintState(SettlePrintState state) {
        SettleInfo settleInfo = mRepository.getSettleInfo();
        settleInfo.setPrintState(state.ordinal());
        mRepository.updateSettleInfo(settleInfo);
    }

    /**
     * 保存结算信息
     *
     * @param
     */
    private void saveSettleInfo() {
        mLog.debug("saveSettleInfo");
        SettleInfo settleInfo = new SettleMapper().transform(mRepository.getSuccessfulTransRecords());
//        SettleInfo settleInfo = new SettleInfo();
        settleInfo.setTerminalId(mRepository.getParamValue(PreferencesConstants.TERMINAL_ID));
        settleInfo.setMerchantId(mRepository.getParamValue(PreferencesConstants.MERCHANT_ID));
        settleInfo.setMerchantName(mRepository.getParamValue(PreferencesConstants.MERCHANT_NAME));
        settleInfo.setBatchNum(mRepository.getParamValue(PreferencesConstants.BATCH_NUMBER));
        settleInfo.setOperator(Integer.parseInt(StringUtils.firstNonEmpty(mRepository.getParamValue(PreferencesConstants.CURRENT_OPERATOR_NO), "1")));
        mRepository.saveSettleInfo(settleInfo);
    }

    /**
     * 保存结算信息
     *
     * @param recvData
     */
    private void saveSettleInfo(RecvData recvData) {
        String  equ = recvData.getRespCode();
        mLog.debug("内卡对帐{}",  "00".equals(equ)  ? "平" : "不平");
        SettleInfo settleInfo = new SettleMapper().transform(mRepository.getSuccessfulTransRecords());
        settleInfo.setIsEqu("00".equals(equ) );
        settleInfo.setIsInterEqu("00".equals(equ) );
        settleInfo.setDate(StringUtils.firstNonEmpty(recvData.getDate(), new SimpleDateFormat("MMdd", SysConstant.LOCALE).format(new Date())));
        settleInfo.setTime(StringUtils.firstNonEmpty(recvData.getTime(), new SimpleDateFormat("HHmmss", SysConstant.LOCALE).format(new Date())));
        settleInfo.setTerminalId(StringUtils.firstNonEmpty(recvData.getTerminalId(), mRepository.getParamValue(PreferencesConstants.TERMINAL_ID)));
        settleInfo.setMerchantId(StringUtils.firstNonEmpty(recvData.getMerchantId(), mRepository.getParamValue(PreferencesConstants.MERCHANT_ID)));
        settleInfo.setMerchantName(mRepository.getParamValue(PreferencesConstants.MERCHANT_NAME));
        settleInfo.setBatchNum(mRepository.getParamValue(PreferencesConstants.BATCH_NUMBER));
        settleInfo.setOperator(Integer.parseInt(StringUtils.firstNonEmpty(mRepository.getParamValue(PreferencesConstants.CURRENT_OPERATOR_NO), "1")));
        mRepository.saveSettleInfo(settleInfo);
    }

    @Override
    public void doSettle() {
        //交易先披上送在结算
        saveSettleInfo();
        postMainThread(() -> mView.showOnlineProc(mTransData, null));
    }

    private void updateSettleStateAndClearTransRecord() {
        mLog.debug("结算完成");
        mRepository.delTotalTransRecord();
        mRepository.increaseBatchNumber();
        updateSettleInfoPrintState(SettlePrintState.CLEAR);
    }

    private void settleComplete() {
        mLog.debug("操作类型 opType = {}", mOpType);
        switch (mOpType) {
            case NORMAL_SETTLE:
            case BATCH_UPLOAD:
                //正常结算流程，判断结算完成后，判断是否自动签退
                mRepository.setParamValue(PreferencesConstants.IS_NEED_LOGIN, "1");
                mRepository.syncParamValue();
                postMainThread(() -> mView.showSettleSuccessfully());
               /* if ("1".equals(mRepository.getParamValue(PreferencesConstants.AUTO_LOGOUT_SWITCH))) {
                    postMainThread(() -> mView.intent2Logout());
                } else {
                    postMainThread(() -> mView.showSettleSuccessfully());
                }*/
                break;
            case LOGOUT_SETTLE:
                //签退前结算，结算完成返回签退界面，继续签退操作
                postMainThread(() -> mView.intent2Logout());
                break;
            case REPRINT_SETTLE_INFO:
                //重打印结算单
                postMainThread(() -> mView.showPrintSuccessfully());
                break;
            default:
                break;
        }
    }

    @Override
    public void startPrintSettle(boolean isRePrint) {
        SettlePrintState printState = getSettlePrintState();
        mLog.debug("结算状态 {},重打 {}", printState, isRePrint);
        if (SettlePrintState.NONE.equals(printState) || isRePrint) {
            //初始化打印机
            int result = PrintHelper.printerCfgInit();
            if (result != SdkResult.Success) {
                postMainThread(() -> mView.showPrintInitErr());
                return;
            }
            //判断打印机是否缺纸
            if (PrintHelper.isPaperLack()) {
                postMainThread(() -> mView.showPrintLackPaper(isRePrint, mOpType));
                return;
            }
            //开始组打印数据
            PrintHelper.formPrintSettleData(mRepository.getSettleInfo(), isRePrint);
            //开始打印
            postMainThread(() -> mView.setPrintingIndicator(true));
            PrintHelper.startPrint(true, retCode -> {
                postMainThread(() -> mView.setPrintingIndicator(false));
                switch (retCode) {
                    case SdkResult.Success:
                        if (SettlePrintState.NONE.equals(printState)) {
                            //先更新结算打印单状态
                            updateSettleInfoPrintState(SettlePrintState.PRINT);
                            //提示是否打印交易明细
                            if ("1".equals(mRepository.getParamValue(PreferencesConstants.PROMPT_PRINT_DETAIL_SWITCH)) && SettleOpType.NORMAL_SETTLE == mOpType) {
                                if (mRepository.getSuccessfulTransRecordNotVoidNum() > 0) {
                                    mLog.debug("需要打印明细");
                                    postMainThread(() -> mView.showWhetherPrintTransDetail(false));
                                    return;
                                } else if (mRepository.getOfflineUploadRejectedTransRecordNum() > 0
                                        || mRepository.getOfflineUploadFailedTransRecordNum() > 0) {
                                    mLog.debug("需要打印失败明细");
                                    postMainThread(() -> mView.showWhetherPrintTransDetail(true));
                                    return;
                                }
                            }
                        }
                        //重新获取状态
                        if (SettlePrintState.PRINT.equals(getSettlePrintState())) {
                            updateSettleStateAndClearTransRecord();
                        }
                        settleComplete();
                        break;
                    case SdkResult.Printer_PaperLack:
                        postMainThread(() -> mView.showPrintLackPaper(isRePrint, mOpType));
                        break;
                    default:
                        postMainThread(() -> mView.showPrintFail(App.sContext.getString(R.string.print_fail)));
                        break;
                }
            });
        } else if (SettlePrintState.PRINT.equals(printState)) {
            updateSettleStateAndClearTransRecord();
            settleComplete();
        } else {
            settleComplete();
        }
    }

    private SettlePrintState getSettlePrintState() {
        SettleInfo settleInfo = mRepository.getSettleInfo();
        return SettlePrintState.values()[settleInfo.getPrintState()];
    }

    @Override
    public void startPrintTransDetail(boolean isErr) {
        if (!isErr) {
            mNowDetailTask = NowDetailTask.DETAIL;
        } else {
            mNowDetailTask = NowDetailTask.UPLOAD_REJECTED_DETAIL;
        }
        printTransDetail();
    }

    private void printTransDetail() {
        mIsCustomerCancel = false;
        //初始化打印机
        PrintHelper.printerCfgInit();
        //判断打印机是否缺纸
        if (PrintHelper.isPaperLack()) {
            postMainThread(() -> mView.showPrintLackPaper(false, null));
            return;
        }
        mLog.debug("明细类型 {}", mNowDetailTask);
        switch (mNowDetailTask) {
            case DETAIL:
                mTransRecordIterator = mRepository.getSuccessfulTransRecords().iterator();
                PrintHelper.formTransDetailHeader();
                break;
            case UPLOAD_REJECTED_DETAIL:
                mTransRecordIterator = mRepository.getOfflineUploadRejectedTransRecords().iterator();
                PrintHelper.formUploadRejectedTransDetailHeader();
                break;
            case UPLOAD_FAILED_DETAIL:
                mTransRecordIterator = mRepository.getOfflineUploadFailedTransRecords().iterator();
                PrintHelper.formUploadFailTransDetailHeader();
                break;
            default:
                break;
        }
        mSubject = BehaviorSubject.create();
        mSubject.doOnNext(transRecord -> mCurrTransRecord = transRecord)
                .doOnSubscribe(transRecord -> printNext(true))
                .doOnComplete(() -> postMainThread(() -> mView.setPrintingIndicator(false)))
                .subscribe(transRecord -> startPrint(transRecord),
                        throwable -> postMainThread(() -> mView.showPrintFail(App.sContext.getString(R.string.print_fail))),
                        () -> printComplete());
    }

    private void printComplete() {
        PrintHelper.cutPaper();
        switch (mNowDetailTask) {
            case DETAIL:
                //提示打印失败明细
                if (mRepository.getOfflineUploadRejectedTransRecordNum() > 0
                        || mRepository.getOfflineUploadFailedTransRecordNum() > 0) {
                    postMainThread(() -> mView.showWhetherPrintTransDetail(true));
                    return;
                }
                break;
            case UPLOAD_REJECTED_DETAIL:
                if (mRepository.getOfflineUploadFailedTransRecordNum() > 0) {
                    mNowDetailTask = NowDetailTask.UPLOAD_FAILED_DETAIL;
                    printTransDetail();
                    return;
                }
                break;
            case UPLOAD_FAILED_DETAIL:
            default:
                break;
        }
        updateSettleInfoPrintState(SettlePrintState.PRINT);
        updateSettleStateAndClearTransRecord();
        settleComplete();
    }

    @Override
    public void cancelPrintDetail() {
        mLog.debug("用户取消打印");
        mIsCustomerCancel = true;
        //lr add
        updateSettleInfoPrintState(SettlePrintState.PRINT);
        updateSettleStateAndClearTransRecord();
        settleComplete();
    }

    @Override
    public void continuePrintDetail() {
        mSubject.onNext(mCurrTransRecord);
    }

    /**
     * 打印下一笔
     */
    private void printNext(boolean firstTime) {
        //lr add
        while (mTransRecordIterator.hasNext() && !mIsCustomerCancel) {
            TransRecord next = mTransRecordIterator.next();
            //lr add已撤销交易不打明细
            if (!TransUtils.isNeedPrintDetail(TransType.values()[next.getTransType()]) || next.getIsVoid()) {
                continue;
            }
            mSubject.onNext(next);
            return;
        }

        if (firstTime) {
            postMainThread(() -> mView.setPrintingIndicator(true));
        }

        mSubject.onComplete();
    }

    /**
     * 开始打印
     *
     * @param transRecord 记录
     */
    private void startPrint(TransRecord transRecord) {
        PrintHelper.formPrintTransDetail(transRecord);
        PrintHelper.startPrint(false, retCode -> {
            switch (retCode) {
                case SdkResult.Success:
                    printNext(false);
                    break;
                case SdkResult.Printer_PaperLack:
                    postMainThread(() -> mView.showPrintLackPaper(false, null));
                    break;
                default:
                    postMainThread(() -> mView.showPrintFail(App.sContext.getString(R.string.print_fail)));
                    mSubject.onComplete();
                    break;
            }
        });
    }

    @Override
    public void startPrintSum() {
        //初始化打印机
        int result = PrintHelper.printerCfgInit();
        if (result != SdkResult.Success) {
            postMainThread(() -> mView.showPrintInitErr());
            return;
        }
        //判断打印机是否缺纸
        if (PrintHelper.isPaperLack()) {
            postMainThread(() -> mView.showPrintLackPaper(false, mOpType));
            return;
        }
        //开始组打印数据
        PrintHelper.formPrintTransSummary(mSettleInfo);
        //开始打印
        postMainThread(() -> mView.setPrintingIndicator(true));
        PrintHelper.startPrint(true, retCode -> {
            postMainThread(() -> mView.setPrintingIndicator(false));
            switch (retCode) {
                case SdkResult.Success:
                    postMainThread(() -> mView.showPrintSuccessfully());
                    break;
                case SdkResult.Printer_PaperLack:
                    postMainThread(() -> mView.showPrintLackPaper(false, mOpType));
                    break;
                default:
                    postMainThread(() -> mView.showPrintFail(App.sContext.getString(R.string.print_fail)));
                    break;
            }
        });
    }

    private enum NowDetailTask {
        /**
         * 成功交易明细
         */
        DETAIL,
        /**
         * 上送被拒明细
         */
        UPLOAD_REJECTED_DETAIL,
        /**
         * 上送失败明细
         */
        UPLOAD_FAILED_DETAIL,
    }
}
